package cn.startom.sjdzpsdk;

import com.alibaba.fastjson.JSONObject;
import javafx.beans.binding.ObjectExpression;
import jdk.nashorn.internal.parser.JSONParser;
import jodd.http.HttpRequest;
import jodd.http.HttpResponse;
import jodd.util.StringUtil;

import javax.management.ValueExp;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.*;

import static java.util.stream.Collectors.toMap;

/**
 * 默认请求执行客户端实现
 * @author  chenzhe
 */
public class DefaultClient implements IClient {

    private int pid;
    private String secret;
    private String domain;

    /**
     * 构造函数
     * @param domain 接口地址
     * @param pid 合作id
     * @param secret  授权码
     */
    public DefaultClient(String domain,int pid,String secret){
        this.domain=domain;
        this.pid=pid;
        this.secret=secret;
    }

    /**
     * 执行请求
     * @param <T>  结果对象
     * @param request 请求对象
     * @param resClass
     * @return
     */
    public <T> T execut(Request request, Class<?> resClass) {
        request.set_pid(this.pid);
        String url=this.domain;
        Map<String, Object> map=getMapParam(request);
        HttpResponse response = HttpRequest
                .post(url)
                .form(map)
                .send();
        return (T)JSONObject.parseObject(response.bodyText(),resClass);
    }

    @Override
    public String buildSign(Map<String, Object> sorted) {
        StringBuilder sb=new StringBuilder();
        sb.append(this.secret);
        for (Map.Entry<String,Object> entry:sorted.entrySet()){
            sb.append("&"+entry.getKey()+"="+entry.getValue());
        }
        sb.append("&"+this.secret);
        //加密
        String unSingStr=sb.toString();
        String sign=CommonUtil.MD5(unSingStr);
        return sign;
    }

    /**
     * 根据对象的值生成参数列表
     * @param request 请求对象
     * @return
     */
    private Map<String, Object> getMapParam(Request request) {
        SimpleDateFormat sf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Map<String,Object> map=new HashMap<>();
        //自己类
        Field[] fields= request.getClass().getDeclaredFields();
        for(int i=0;i<fields.length;i++){
            Field field=fields[i];
            int mod = field.getModifiers();
            if (Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
                continue;
            }
            try{
                field.setAccessible(true);
                String fieldName=field.getName();
                Object value=field.get(request);
                if(value==null)
                    continue;
                else if(value.toString().equals("0"))
                    continue;
                String valStr=null;
                Class<?> cls= field.getType();

                if(cls.isArray())
                {
                    //数组类型需要拆分
                    Map<String,String> itemArr=getMapFromArray(fieldName,value,value.getClass().getComponentType());
                    map.putAll(itemArr);
                    continue;
                }
                else if(value instanceof Date)
                    valStr=sf.format(value);
                else
                    valStr=value.toString();
                map.put(fieldName,valStr);
            }catch (IllegalAccessException e){
                e.printStackTrace();
            }
        }
        //基类的赋值
        fields= request.getClass().getSuperclass().getDeclaredFields();
        for(int i=0;i<fields.length;i++){
            Field field=fields[i];
            int mod = field.getModifiers();
            if (Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
                continue;
            }
            try{
                field.setAccessible(true);
                String fieldName=field.getName();
                Object value=field.get(request);
                if(value==null)
                    continue;
                else if(value.toString().equals("0"))
                    continue;
                String valStr=null;
                if(value instanceof Date)
                    valStr= value.toString();
                else
                    valStr=value.toString();
                map.put(fieldName,valStr);
            }catch (IllegalAccessException e){
                e.printStackTrace();
            }
        }
        //排序
        Map<String,Object> sorted;
        sorted = map.entrySet()
                .stream()
                .sorted(CommonUtil.comparatorByKeyAsc)
                .collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e2,
                        LinkedHashMap::new));
        //获取签名
        String sign=buildSign(sorted);
        map.put("_sig",sign);
        return map;
    }

    /**
     * 根据数组对象创建数组map符合form提交格式
     * @param value 数组对象实例
     * @return
     */
    private <T> Map<String, String> getMapFromArray(String prefixName,Object value,Class<?> cls) {
       T[] arr=(T[])value;
       Map<String,String> map=new HashMap<>();
       if(arr!=null)
       {
          Field[] fields=  cls.getDeclaredFields();

          for (int i=0;i<arr.length;i++){
              T obj=arr[i];
              for (int j=0;j<fields.length;j++){
                  Field field=fields[j];
                  try{
                      field.setAccessible(true);
                      String fieldName=field.getName();
                      Object val=field.get(obj);
                      if(val==null)
                          continue;
                      else if(val.toString().equals("0"))
                          continue;
                      String valStr=null;
                      if(val instanceof Date)
                          valStr= val.toString();
                      else
                          valStr=val.toString();
                      String key=String.format("%s[%d][%s]",prefixName,i,fieldName);
                      map.put(key,valStr);
                  }catch (IllegalAccessException e){
                      e.printStackTrace();
                  }

              }
          }
       }
       return map;
    }


}
